Skip to content

Conversation

BioPhoton
Copy link
Collaborator

@BioPhoton BioPhoton commented Sep 8, 2025

This PR includes:

  • move all command helper into 1 file - command.ts
  • adjust executeProgress - removed hard dependencies to other functions so it is easier to use in nx-plugin
  • copied command.ts and executeProcess.ts into nx-plugin project and marked them

Copy link
Contributor

github-actions bot commented Sep 16, 2025

Code PushUp

🤨 Code PushUp report has both improvements and regressions – compared current commit e512344 with previous commit 33714e2.

🕵️ See full comparison in Code PushUp portal 🔍

🏷️ Categories

🏷️ Category ⭐ Previous score ⭐ Current score 🔄 Score change
Performance 🔴 36 🔴 28 ↓ −8
Code coverage 🟡 90 🟡 89 ↓ −0.7
Updates 🟡 84 🟡 84 ↓ −0.2
Documentation 🔴 24 🔴 25 ↑ +0.1
Security 🟡 56 🟡 56
Accessibility 🟢 92 🟢 92
Best Practices 🟢 100 🟢 100
SEO 🟡 61 🟡 61
Type Safety 🟢 100 🟢 100
Bug prevention 🟢 100 🟢 100
Miscellaneous 🟢 100 🟢 100
Code style 🟢 100 🟢 100
👍 1 group improved, 👎 3 groups regressed, 👍 2 audits improved, 👎 9 audits regressed, 12 audits changed without impacting score

🗃️ Groups

🔌 Plugin 🗃️ Group ⭐ Previous score ⭐ Current score 🔄 Score change
Lighthouse Performance 🔴 36 🔴 28 ↓ −8
Code coverage Code coverage metrics 🟡 90 🟡 89 ↓ −0.7
JS Packages NPM outdated dependencies 🟡 84 🟡 84 ↓ −0.2
JSDoc coverage Documentation coverage 🔴 24 🔴 25 ↑ +0.1

17 other groups are unchanged.

🛡️ Audits

🔌 Plugin 🛡️ Audit 📏 Previous value 📏 Current value 🔄 Value change
Lighthouse Initial server response time was short 🟩 Root document took 600 ms 🟥 Root document took 750 ms ↑ +25 %
Lighthouse First Contentful Paint 🟥 3.3 s 🟥 4.4 s ↑ +35 %
Lighthouse Speed Index 🟥 7.2 s 🟥 9.6 s ↑ +33.8 %
Lighthouse Total Blocking Time 🟥 1,640 ms 🟥 5,470 ms ↑ +234.6 %
Lighthouse Time to Interactive 🟥 13.6 s 🟥 15.6 s ↑ +14.7 %
JS Packages Outdated NPM dev dependencies. 🟨 59 outdated package versions (27 major, 24 minor, 8 patch) 🟨 59 outdated package versions (28 major, 23 minor, 8 patch)  +0 %
Code coverage Function coverage 🟩 92.5 % 🟩 91.4 % ↓ −1.2 %
JSDoc coverage Functions coverage 🟥 521 undocumented functions 🟥 521 undocumented functions  +0 %
Code coverage Line coverage 🟨 86.3 % 🟨 85.8 % ↓ −0.6 %
JSDoc coverage Types coverage 🟥 241 undocumented types 🟥 243 undocumented types ↑ +0.8 %
Code coverage Branch coverage 🟨 85.5 % 🟨 85.6 % ↑ +0.1 %
Lighthouse Minimizes main-thread work 🟥 11.9 s 🟥 20.4 s ↑ +71.9 %
Lighthouse JavaScript execution time 🟥 5.0 s 🟥 8.0 s ↑ +59.9 %
Lighthouse Largest Contentful Paint 🟥 11.3 s 🟥 13.5 s ↑ +19.7 %
Lighthouse Metrics 🟩 100% 🟩 100% ↑ +14.7 %
Lighthouse Max Potential First Input Delay 🟥 1,390 ms 🟥 2,880 ms ↑ +106.8 %
Lighthouse Uses efficient cache policy on static assets 🟨 30 resources found 🟨 30 resources found ↓ −0.1 %
Lighthouse Avoids enormous network payloads 🟩 Total size was 2,039 KiB 🟩 Total size was 2,039 KiB ↓ −0.1 %
Lighthouse Remove duplicate modules in JavaScript bundles 🟥 Potential savings of 78 KiB 🟥 Potential savings of 98 KiB ↑ +50 %
Lighthouse Server Backend Latencies 🟩 1,540 ms 🟩 1,400 ms ↓ −9.2 %
Lighthouse Network Round Trip Times 🟩 50 ms 🟩 70 ms ↑ +50 %
Lighthouse Reduce unused CSS 🟥 Potential savings of 102 KiB 🟥 Potential savings of 102 KiB ↓ −2.2 %
JS Packages Vulnerabilities for NPM dev dependencies. 🟥 11 vulnerabilities (1 critical, 5 moderate, 5 low) 🟥 15 vulnerabilities (1 critical, 5 moderate, 9 low) ↑ +36.4 %

587 other audits are unchanged.

@BioPhoton BioPhoton marked this pull request as ready for review October 4, 2025 11:10
@BioPhoton BioPhoton requested a review from matejchalk as a code owner October 4, 2025 11:10
return new Promise((resolve, reject) => {
// shell:true tells Windows to use shell command for spawning a child process
const process = spawn(command, args, { cwd, shell: true });
const spawnedProcess = spawn(command, args ?? [], {

Check warning

Code scanning / CodeQL

Unsafe shell command constructed from library input Medium

This shell argument which depends on
library input
is later used in a
shell command
.

Copilot Autofix

AI 6 days ago

To fix this, we should not use { shell: true } with arguments provided directly by untrusted/library input. Instead, we should use { shell: false } (the default), allowing spawn to pass the command and arguments directly to the process without interpretation by the shell. If there are legitimate use cases requiring shell features (such as pipes, I/O redirection), then inputs embedded in the shell command line must be safely escaped using a library like shell-quote. But for generic process execution, switching to non-shell mode is safest.

Thus:

  • In packages/nx-plugin/src/internal/execute-process.ts, at line 175, remove or change shell: true to either omit it or set shell: false.
  • No other code needs changing, unless shell features are known to be required for all usage (which is not demonstrated here).

Alternatively, if some processes require shell interpretation and others do not, expose { shell: true/false } as an explicit configurable option, and document the dangers, but set default to false.

Suggested changeset 1
packages/nx-plugin/src/internal/execute-process.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/nx-plugin/src/internal/execute-process.ts b/packages/nx-plugin/src/internal/execute-process.ts
--- a/packages/nx-plugin/src/internal/execute-process.ts
+++ b/packages/nx-plugin/src/internal/execute-process.ts
@@ -173,7 +173,6 @@
   return new Promise((resolve, reject) => {
     // shell:true tells Windows to use shell command for spawning a child process
     const spawnedProcess = spawn(command, args ?? [], {
-      shell: true,
       windowsHide: true,
       ...options,
     }) as ChildProcessByStdio<Writable, Readable, Readable>;
EOF
@@ -173,7 +173,6 @@
return new Promise((resolve, reject) => {
// shell:true tells Windows to use shell command for spawning a child process
const spawnedProcess = spawn(command, args ?? [], {
shell: true,
windowsHide: true,
...options,
}) as ChildProcessByStdio<Writable, Readable, Readable>;
Copilot is powered by AI and may make mistakes. Always verify output.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a comment that we need it for windows (I'm not sure what exactly the reason was :D)

command: string;
args?: string[];
observer?: ProcessObserver;
verbose?: boolean;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding verbose: isVerbose() to each usage is quite error-prone. We lose the advantage of setting CP_VERBOSE once and then having all process executions automatically logged or not consistently. 😬

However, I understand you're trying to make the implementation as isolated as possible, to make it easier to maintain a copy.

I think there may be a better solution. CJS can't statically import ESM with require 1, but CJS can dynamically import ESM. For many synchronous utility functions, this would be a little inconvenient - code would need to become async because of await import('@code-pushup/utils') - but executeProcess is already asynchronous, so there isn't really any downside.

const { executeProcess } = await import('@code-pushup/utils');
await executeProcess(...);

For convenience, you could implement a simple wrapper to deduplicate usage across @code-pushup/nx-plugin:

// somewhere in nx-plugin's internal utils

// same function signature => exact same usage
export async function executeProcess(cfg: ProcessConfig): Promise<ProcessResult> {
  // CJS-compatible import
  const utils = await import('@code-pushup/utils');
  // no duplicated logic, call original code
  return utils.executeProcess(cfg);
}
Experiments with importing ESM into CJS
// utils.mjs

// top-level await to break require(esm) in modern Node
await new Promise(resolve => {
  setTimeout(resolve, 500);
});

// ESM syntax
export function greet(name = 'world') {
  console.log(`Hello, ${name}!`);
}
// nx-plugin.cjs

// ❌ THIS DOESN'T WORK (ERR_REQUIRE_ESM or ERR_REQUIRE_ASYNC_MODULE)
const { greet } = require('./utils.mjs');
greet('Nx plugin');
// nx-plugin.cjs

// ✅ THIS WORKS
import('./utils.mjs').then(({ greet }) => {
  greet('Nx plugin');
});

Footnotes

  1. Technically, CJS can statically require ESM if running a newer Node version (22+, I believe) and there's no top-level await anywhere in the imported module. Unfortunately, because we want to maintain compatibility for users running older Node versions, the minimum version is probably a deal-breaker for us at the moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants